<template>
	<div>
		<div class="header">
			<slot v-if="showSearch" name="search"></slot>
			<div class="dashed mb-2"></div>
			<div class="flex justify-between pb-2">
				<div>
					<template v-for="(item, i) in headerButs">
						<has-permi
							:permi="item.permi"
							v-if="!(item.visible === false)"
							:key="i"
						>
							<template v-if="item.enable == 1">
								<el-button
									@click="butClickEvent(item, getPickonList)"
									:type="item.color"
									plain
									size="default"
									:disabled="getPickonList.length !== 1"
									:icon="item.icon"
								>
									{{ item.name }}
								</el-button>
							</template>
							<template v-else-if="item.enable == 2">
								<el-button
									@click="butClickEvent(item, getPickonList)"
									:type="item.color"
									plain
									size="default"
									:disabled="getPickonList.length === 0"
									:icon="item.icon"
								>
									{{ item.name }}
								</el-button>
							</template>
							<el-button
								@click="butClickEvent(item, getPickonList)"
								v-else
								:type="item.color"
								plain
								size="default"
								:icon="item.icon"
							>
								{{ item.name }}
							</el-button>
						</has-permi>
					</template>
				</div>
				<right-toolbar
					v-if="toolbar"
					v-model:showSearch="showSearch"
					@queryTable="fetchData"
					@transferUpdate="transferUpdate"
					:columns="transferColumns"
				></right-toolbar>
			</div>
			<slot name="total"></slot>
		</div>

		<el-table
			ref="table"
			v-loading="loading"
			:data="tableList"
			:height="tableHeight"
			:stripe="stripe"
			:border="border"
			:size="size"
			:show-header="showHeader"
			:highlight-current-row="highlightCurrentRow"
			:default-expand-all="expandAll"
			:span-method="spanMethod"
			@sort-change="sortChange"
			@select-all="toggleSelectAll"
			:row-key="rowKey"
			:tree-props="treeProps"
		>
			<template v-for="item in columns">
				<el-table-column
					:type="item.type"
					:key="item.field"
					:prop="item.field"
					:label="item.field"
					:width="setColumnWidth(item)"
					:fixed="item.fixed"
					:show-overflow-tooltip="item.overflowTooltip"
					:align="item.align || 'left'"
					:class-name="item.className"
					:label-class-name="item.labelClassName"
					:sortable="item.sortable"
					v-if="!(item.visible === false)"
				>
					<!-- 自定义表头 -->
					<template #header>
						<slot :name="`${item.field}Header`" :row="item">
							<span @click="handlerHeaderRow(item.field, item)">
								{{ item.title }}
							</span>
						</slot>
					</template>
					<!-- 表体 -->
					<template #default="scope">
						<span v-if="item.type == 'index'">
							{{
								pageNum == 1
									? scope.$index + 1
									: (pageNum - 1) * pageSize + scope.$index + 1
							}}
						</span>
						<el-checkbox
							v-if="item.type == 'selection'"
							v-model="scope.row['selection']"
						></el-checkbox>
						<el-radio
							@click="radioChange(scope.$index)"
							v-if="item.type == 'radio'"
							:label="true"
							v-model="scope.row['selection']"
						></el-radio>
						<slot :name="item.field" :row="scope.row">
							<!-- 图片预览 -->
							<template v-if="item.preview">
								<el-image
									v-if="scope.row[item.field]"
									style="width: 30px; height: 30px"
									:src="base64Handle(scope.row[item.field])"
									:preview-src-list="[base64Handle(scope.row[item.field])]"
									preview-teleported
								></el-image>
							</template>
							<span v-else @click="handlerTableRow(item.field, scope.row)">
								{{
									item.formatter
										? item.formatter(scope.row[item.field], scope.row)
										: scope.row[item.field]
								}}
							</span>
						</slot>
					</template>
				</el-table-column>
			</template>
			<el-table-column
				label="操作"
				:width="tableButsWidth"
				:align="tableButsAlign"
				fixed="right"
				v-if="tableButs && tableButs?.length > 0"
			>
				<template #default="scope">
					<template v-for="(item, i) in tableButs" :key="i">
						<has-permi
							:permi="item.permi"
							:key="i"
							v-if="!(item.visible === false)"
						>
							<el-button
								:class="`table-but-${uuid}`"
								@click="butClickEvent(item, [scope.row])"
								link
								:type="item.color"
								size="default"
								:icon="item.icon"
							>
								{{
									item.formatter
										? item.formatter(scope.row, item.name)
										: item.name
								}}
							</el-button>
						</has-permi>
					</template>
				</template>
			</el-table-column>
		</el-table>
		<el-row
			v-if="hasPage"
			class="pagination py-1"
			type="flex"
			:justify="pagingJustify"
		>
			<el-pagination
				background
				:page-size="pageSize"
				:total="total"
				v-model:current-page="pageNum"
				layout="total,prev,pager,next, sizes, jumper, slot"
				:page-sizes="pageSizes"
				@size-change="handlerSizeChange"
				@current-change="handlerCurrentChange"
			></el-pagination>
		</el-row>
	</div>
</template>
<script lang="ts" setup>
	import RightToolbar from '@/components/RightToolbar/index.vue';
	import { v4 as uuidv4 } from 'uuid';
	import {
		defineProps,
		defineExpose,
		ref,
		computed,
		onMounted,
		nextTick,
		onUnmounted,
	} from 'vue';
	import type { PropType } from 'vue';

	type ButsType = {
		butType: string;
		name: string;
		color: string;
		visible?: boolean;
		permi: Array<string>;
		icon: string;
		enable: '1' | '2' | 1 | 2 | '';
		formatter: (value: any, row: any) => string;
	};

	type ColumnsType = {
		title: string;
		field: string;
		overflowTooltip?: boolean;
		fixed?: boolean;
		type?: 'expand' | 'index' | 'selection' | 'radio';
		width?: number;
		formatter?: (value: any, row: any) => string;
		align?: 'left' | 'center' | 'right';
		className?: string;
		labelClassName?: string;
		sortable?: boolean;
		visible?: boolean;
		preview?: boolean;
	};
	const props = defineProps({
		// 是否展示talbe上面部分
		isHeader: {
			type: Boolean,
			default: true,
		},
		/**
		 * 头部操作按钮
		 *  butType 唯一key
		 *  enable: '' 操作按钮禁用状态 1 选中一个启用 ｜  2 选中一个或者多个启用 ｜  默认不限制
		 *  name: "", // 文字
		 *  color: "", // 颜色
		 *  permi: [], // 权限
		 *  icon: "", // 图标
		 *  visible:'true' // 是否展示
		 */
		headerButs: {
			type: Array as PropType<Array<Omit<ButsType, 'formatter'>>>,
		},
		/**
		 * 列表操作项
		 *  butType 唯一key
		 *  name: "", // 文字
		 *  color: "", // 颜色
		 *  permi: [], // 权限
		 *  icon: "", // 图标
		 * 	visible:'true' // 是否展示
		 *  formatter:(val)=>{} // 数据格式化
		 *
		 */
		tableButs: {
			type: Array as PropType<Array<Omit<ButsType, 'enable'>>>,
		},
		// 列表操作项对齐方式 left|center|right
		tableButsAlign: {
			type: String as PropType<'left' | 'center' | 'right'>,
			default: 'center',
		},
		/**
		 * 表头信息
		 * type: expand 展开 |index 序号|selection 多选|radio 单选
		 * title: 表头标题
		 * field: 渲染列表的key
		 * width: 表格宽
		 * formatter: 格式化函数
		 * overflowTooltip：超出文字展示...,
		 * align: 对齐方式 left | center | right
		 * className: 列的 className
		 * labelClassName: 当前列标题的自定义类名
		 * sortable:'true' // 排序
		 * visible:'true' // 是否展示
		 * preview:'true' // 图片预览
		 * field+Header: 表头插槽
		 * field: 表格插槽
		 */
		columns: {
			type: Array as PropType<Array<ColumnsType>>,
			required: true,
		},
		// 是否自动加载接口
		initApi: {
			type: Boolean,
			default: true,
		},
		// 查询接口
		reqApiMethod: {
			type: Function,
			required: true,
		},
		// 查询参数
		searchParams: {
			type: Object,
			// eslint-disable-next-line vue/require-valid-default-prop
			default: {},
		},
		// 格式化接口入参
		requestHandler: {
			type: Function,
			default(params = {}) {
				return params;
			},
		},
		// 格式化数据接口返回的数据
		responseHandler: {
			type: Function,
			default(res) {
				return res;
			},
		},
		// 操作按钮点击
		butClickEvent: {
			type: Function,
			default() {},
		},
		// 固定表头
		fixedheader: {
			type: Boolean,
			default: true,
		},
		// 是否展示工具
		toolbar: {
			type: Boolean,
			default: true,
		},
		// 是否分页
		hasPage: {
			type: Boolean,
			default: true,
		},
		// 每页展示条数
		pageSize: {
			type: Number,
			default: 10,
		},
		// 选择每一个展示的条数
		pageSizes: {
			type: Array,
			default: () => [10, 20, 30, 40, 50],
		},
		// 分页的位置展示
		pagingJustify: {
			type: String,
			default: 'end',
		},
		// Table 的高度
		height: {
			type: [String, Number],
		},
		// 是否为斑马纹 table
		stripe: {
			type: Boolean,
			default: false,
		},
		// 是否带有纵向边框
		border: {
			type: Boolean,
			default: false,
		},
		// 是否显示表头
		showHeader: {
			type: Boolean,
			default: true,
		},
		// Table 的尺寸
		size: {
			type: String,
			default: 'default',
		},
		// 是否要高亮当前行
		highlightCurrentRow: {
			type: Boolean,
			default: false,
		},
		// 树形table key
		rowKey: {
			type: String,
			default: 'id',
		},
		// 渲染嵌套数据的配置选项
		treeProps: {
			type: Object,
			default: () => {
				return { hasChildren: 'hasChildren', children: 'children' };
			},
		},
		// table单元格点击
		handlerTableRow: {
			type: Function,
		},
		// table表头点击
		handlerHeaderRow: {
			type: Function,
		},
		// 是否默认展开所有行，当 Table 包含展开行存在或者为树形表格时有效
		expandAll: {
			type: Boolean,
			default: false,
		},
		// 合并行或列的计算方法
		mergeTable: {
			type: Function,
		},
	});
	let uuid = uuidv4();
	let loading = ref(false);
	let tableHeight = ref<any>(props.height);
	// 显示搜索条件
	let showSearch = ref(true);
	// 实例
	let table = ref();
	// 当前页
	let pageNum = ref(1);
	// 每页展示条数
	let pageSize = ref(props.pageSize);
	// 总条数
	let total = ref(0);
	// 列表数据
	let tableList = ref<any>([]);
	// 选择的数据
	let getPickonList = computed(() => {
		return tableList.value.filter(item => item.selection);
	});
	// 列显隐信息
	let transferColumns = computed(() => {
		return props.columns
			.filter(item => item.field && item.title)
			.map(item => {
				return {
					key: item.field,
					label: item.title,
					visible: true,
				};
			});
	});

	let transferUpdate = data => {
		if (data.length === 0) {
			props.columns.forEach(item => {
				item.visible = true;
			});
		} else {
			props.columns.forEach(item => {
				// 如果存在key隐藏
				item.visible = !data.includes(item.field);
			});
		}
		refreshLayout();
	};

	// 获取列表数据
	let fetchData = async ({ isResetPageNumber = false } = {}) => {
		return new Promise<void>(resolve => {
			loading.value = true;
			// 搜索重置页数
			if (isResetPageNumber) {
				pageNum.value = 1;
			}
			// 过滤空数据
			let searchParams = {};
			Object.keys(props.searchParams).forEach(key => {
				if (
					props.searchParams[key] !== '' &&
					props.searchParams[key] !== 'null' &&
					props.searchParams[key] !== 'undefined' &&
					props.searchParams[key] !== null &&
					props.searchParams[key] !== undefined
				) {
					searchParams[key] = props.searchParams[key];
				}
			});
			let queryForm = props.requestHandler({
				pageNum: pageNum.value,
				pageSize: pageSize.value,
				...searchParams,
			});
			// 日期开始结束时间处理
			if (
				Array.isArray(queryForm.dateRange) &&
				queryForm.dateRange.length > 0
			) {
				queryForm.startDate = queryForm.dateRange[0];
				queryForm.endDate = queryForm.dateRange[1];
				delete queryForm.dateRange;
			}
			if (!props.hasPage) {
				delete queryForm.pageNum;
				delete queryForm.pageSize;
			}
			props
				.reqApiMethod(queryForm)
				.then(res => {
					loading.value = false;
					total.value = res.total;
					let rows = props.responseHandler(res.rows);
					tableList.value = rows.map(item => {
						return {
							...item,
							selection: false,
						};
					});
					resolve();
				})
				.catch(() => {
					loading.value = false;
					resolve();
				});
		});
	};
	// 表格宽
	let setColumnWidth = ({ type, width }: ColumnsType) => {
		if (width) {
			return width;
		}
		return type === 'radio' || type === 'selection' ? '30px' : '';
	};

	// 计算高度
	let onResize = () => {
		if (!props.fixedheader) return;
		let clientHeight = document.body.clientHeight;
		let headerHeight = document.querySelector('.header')?.clientHeight || 0;
		let paginationHeight = 0;

		try {
			paginationHeight =
				document.querySelector('.pagination')?.clientHeight || 0;
		} catch (error) {
			console.warn(error);
		}
		tableHeight.value = clientHeight - headerHeight - paginationHeight;
	};
	//   列表操作项宽
	let tableButsWidth = ref(0);
	onMounted(() => {
		nextTick(() => {
			let tableButs = document.querySelectorAll(`.table-but-${uuid}`);
			tableButsWidth.value = Array.from(tableButs).reduce(
				(previousValue, item) => {
					return previousValue + item.clientWidth;
				},
				tableButs.length * 30
			);
		});
		if (props.fixedheader) {
			onResize();
			window.addEventListener('resize', onResize);
		}
	});

	onUnmounted(() => {
		window.removeEventListener('resize', onResize);
	});

	if (props.initApi) {
		Promise.resolve().then(() => fetchData());
	}

	// Base64处理
	let base64Handle = imgRrc => {
		return imgRrc;
	};

	// 每页条数改变
	let handlerSizeChange = val => {
		pageSize.value = val;
		fetchData();
	};
	// 页数改变
	let handlerCurrentChange = val => {
		pageNum.value = val;
		fetchData();
	};

	// 当表格的排序条件发生变化的时候会触发该事件
	let sortChange = ({ column, prop, order }) => {
		console.log(column, prop, order);
	};

	// 全选/反选
	let toggleSelectAll = list => {
		tableList.value.forEach(item => (item.selection = list.length !== 0));
	};
	// 单选
	let radioChange = index => {
		tableList.value.forEach((item, i) => {
			item.selection = i === index;
		});
	};

	// 表头点击操作
	let handlerHeaderRow = (key, row) => {
		if (props.handlerHeaderRow) {
			props.handlerHeaderRow(key, row);
		}
	};

	// table单元格点击
	let handlerTableRow = (key, row) => {
		if (props.handlerTableRow) {
			props.handlerTableRow(key, row);
		}
	};

	// 合并行或列的计算方法
	let spanMethod = ({ row, column, rowIndex, columnIndex }) => {
		if (props.mergeTable) {
			return props.mergeTable({ row, column, rowIndex, columnIndex });
		}
	};

	// 重置布局
	let refreshLayout = () => {
		nextTick(() => {
			table.value.doLayout();
		});
	};
	defineExpose({
		refreshLayout,
		fetchData,
	});
</script>

<style lang="scss" scoped>
	:deep(.el-pagination__sizes) {
		margin-left: 10px !important;
	}
</style>
